﻿#include <hpdf.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <codecvt>
#include <locale>

// 错误处理函数
void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no, void* user_data) {
    std::cerr << "ERROR: error_no=" << error_no << ", detail_no=" << detail_no << std::endl;
}

// 获取字体中实际支持的字符
std::set<std::string> get_characters_from_font(const char* font_path) {
    std::set<std::string> characters;
    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;

    // 初始化 FreeType 库
    FT_Library library;
    if (FT_Init_FreeType(&library)) {
        std::cerr << "Failed to initialize FreeType library." << std::endl;
        return characters;
    }

    // 加载字体文件
    FT_Face face;
    if (FT_New_Face(library, font_path, 0, &face)) {
        std::cerr << "Failed to load font file: " << font_path << std::endl;
        FT_Done_FreeType(library);
        return characters;
    }

    // 遍历字体中的所有字符
    FT_UInt glyph_index;
    FT_ULong char_code = FT_Get_First_Char(face, &glyph_index);
    while (glyph_index != 0) {
        try {
            // 将 Unicode 编码转换为字符
            std::string character = converter.to_bytes(char_code);
            characters.insert(character);
        }
        catch (const std::range_error&) {
            // 忽略无效的 Unicode 编码
        }

        // 获取下一个字符
        char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
    }

    // 释放资源
    FT_Done_Face(face);
    FT_Done_FreeType(library);

    return characters;
}

// 生成 PDF 文件
void generate_pdf(const std::set<std::string>& characters, const char* font_path, const char* output_path) {
    // 创建 PDF 文档对象
    HPDF_Doc pdf = HPDF_New(error_handler, nullptr);
    if (!pdf) {
        std::cerr << "Failed to create PDF document." << std::endl;
        return;
    }

    // 设置 PDF 文档属性
    HPDF_SetCompressionMode(pdf, HPDF_COMP_ALL);
    HPDF_UseUTFEncodings(pdf);

    // 加载字体文件
    const char* font_name = HPDF_LoadTTFontFromFile(pdf, font_path, HPDF_TRUE);
    HPDF_Font font = HPDF_GetFont(pdf, font_name, "UTF-8");
    if (!font) {
        std::cerr << "Failed to load font: " << font_name << std::endl;
        HPDF_Free(pdf);
        return;
    }

    // 将字符集合转换为字符列表
    std::vector<std::string> char_list(characters.begin(), characters.end());

    // 每页写入 300 个字符，每行写入 15 个字符
    for (size_t page_start = 0; page_start < char_list.size(); page_start += 300) {
        // 创建新页面
        HPDF_Page page = HPDF_AddPage(pdf);
        HPDF_Page_SetSize(page, HPDF_PAGE_SIZE_A4, HPDF_PAGE_PORTRAIT);

        // 设置字体和字号
        const float font_size = 12;
        HPDF_Page_SetFontAndSize(page, font, font_size);

        // 设置页边距
        const float margin = 50;
        float x = margin;
        float y = HPDF_Page_GetHeight(page) - margin;

        // 写入字符
        for (size_t i = page_start; i < page_start + 300 && i < char_list.size(); ++i) {
            if ((i - page_start) % 15 == 0 && i != page_start) {
                // 换行
                y -= font_size * 1.5; // 行高
                x = margin;
            }

            // 写入单个字符
            HPDF_Page_BeginText(page);
            HPDF_Page_TextOut(page, x, y, char_list[i].c_str());
            HPDF_Page_EndText(page);

            x += font_size; // 字符间距
        }
    }

    // 保存 PDF 文件
    if (HPDF_SaveToFile(pdf, output_path) != HPDF_OK) {
        std::cerr << "Failed to save PDF file: " << output_path << std::endl;
    }

    // 释放资源
    HPDF_Free(pdf);
}

int main() {
    // 字体文件路径
    const char* font_path = "simkai.ttf";

    // 获取字体中实际支持的字符
    std::set<std::string> characters = get_characters_from_font(font_path);
    if (characters.empty()) {
        std::cerr << "No characters found in font file: " << font_path << std::endl;
        return 1;
    }

    // 生成 PDF 文件
    const char* output_path = "kai.pdf";
    std::cout << "Generating PDF..." << std::endl;
    generate_pdf(characters, font_path, output_path);
    std::cout << "PDF generated successfully: " << output_path << std::endl;

    return 0;
}